package auth

import (
	"douhu_backend/internal/errors"
	"douhu_backend/internal/infra/logger"
	"douhu_backend/internal/model/auth"
	"time"
)

// PhoneLoginRequest 手机号登录请求
type PhoneLoginRequest struct {
	Phone    string `json:"phone" validate:"required"`
	Code     string `json:"code" validate:"required"`
	ClientIP string `json:"client_ip"`
}

// LoginData 登录成功返回的数据
type LoginData struct {
	AccessToken      string     `json:"access_token"`
	RefreshToken     string     `json:"refresh_token"`
	User             *auth.User `json:"user"`
	AccessExpiresAt  time.Time  `json:"access_expires_at"`
	RefreshExpiresAt time.Time  `json:"refresh_expires_at"`
}

// PhoneLogin 手机号登录
// 返回 (*LoginData, error)
// - 成功: 返回 (LoginData, nil)
// - 失败: 返回 (nil, ServiceError)
func (s *Service) PhoneLogin(req *PhoneLoginRequest) (*LoginData, error) {
	// 1. 验证手机号格式
	if !s.validatePhone(req.Phone) {
		return nil, errors.ErrPhoneFormat
	}

	// 2. 获取 DAO 管理器
	daoManager := s.manager.GetDAOManager()
	authDAO := daoManager.Auth

	// 3. 检查是否被锁定
	loginLimit, err := authDAO.GetLoginLimit(req.Phone)
	if err == nil && loginLimit != nil {
		if time.Now().Before(loginLimit.LockExpTime) {
			waitSeconds := int(time.Until(loginLimit.LockExpTime).Seconds())
			return nil, errors.NewLoginLockedError(loginLimit.LockExpTime, waitSeconds)
		}
	}

	// 4. 验证短信验证码
	smsCode, err := authDAO.GetValidSMSCode(req.Phone, auth.SMSCodeTypeLogin)
	if err != nil {
		if authDAO.IsRecordNotFound(err) {
			// 记录失败尝试
			_ = authDAO.CreateLoginAttempt(&auth.LoginAttempt{
				Phone:         req.Phone,
				AttemptTime:   time.Now(),
				IsSuccess:     false,
				FailureReason: "code not found or expired",
				ClientIP:      req.ClientIP,
				AttemptType:   auth.LoginAttemptTypeSMS,
			})

			// 检查失败次数，决定是否锁定
			failCount, _ := authDAO.GetFailedLoginCount(req.Phone, 15*time.Minute)
			if failCount >= 4 { // 包含当前这次，总共5次
				lockExpTime := time.Now().Add(30 * time.Minute)
				_ = authDAO.CreateOrUpdateLoginLimit(&auth.LoginLimit{
					Phone:        req.Phone,
					FailureCount: int(failCount) + 1,
					LockExpTime:  lockExpTime,
					LastFailTime: time.Now(),
				})
				waitSeconds := int(time.Until(lockExpTime).Seconds())
				return nil, errors.NewLoginLockedError(lockExpTime, waitSeconds)
			}

			return nil, errors.ErrCodeNotFound
		}
		logger.Errorf("Get SMS code failed: %v", err)
		return nil, errors.ErrSystem
	}

	// 5. 验证码是否正确
	if smsCode.Code != req.Code {
		// 记录失败尝试
		_ = authDAO.CreateLoginAttempt(&auth.LoginAttempt{
			Phone:         req.Phone,
			AttemptTime:   time.Now(),
			IsSuccess:     false,
			FailureReason: "invalid code",
			ClientIP:      req.ClientIP,
			AttemptType:   auth.LoginAttemptTypeSMS,
		})

		// 检查失败次数
		failCount, _ := authDAO.GetFailedLoginCount(req.Phone, 15*time.Minute)
		if failCount >= 4 {
			lockExpTime := time.Now().Add(30 * time.Minute)
			_ = authDAO.CreateOrUpdateLoginLimit(&auth.LoginLimit{
				Phone:        req.Phone,
				FailureCount: int(failCount) + 1,
				LockExpTime:  lockExpTime,
				LastFailTime: time.Now(),
			})
			waitSeconds := int(time.Until(lockExpTime).Seconds())
			return nil, errors.NewLoginLockedError(lockExpTime, waitSeconds)
		}

		return nil, errors.ErrCodeWrong
	}

	// 6. 标记验证码为已使用
	if err := authDAO.MarkSMSCodeUsed(smsCode.ID, time.Now()); err != nil {
		logger.Errorf("Mark SMS code used failed: %v", err)
		return nil, errors.ErrSystem
	}

	// 7. 查找用户（不再自动注册）
	var user *auth.User
	user, err = authDAO.GetUserByPhone(req.Phone)
	if err != nil {
		if authDAO.IsRecordNotFound(err) {
			// 用户不存在，提示先注册
			return nil, errors.ErrUserNotFound
		}
		logger.Errorf("Get user by phone failed: %v", err)
		return nil, errors.ErrSystem
	}

	// 8. 检查用户状态
	if user.Status == auth.UserStatusDisabled {
		return nil, errors.ErrUserDisabled
	}

	// 9. 更新最后登录信息
	if err := authDAO.UpdateUserLastLogin(user.ID, req.ClientIP, time.Now()); err != nil {
		logger.Errorf("Update user last login failed: %v", err)
	}

	// 10. 生成 JWT Token对
	jwtService := s.JWT()
	tokenPair, err := jwtService.GenerateTokenPair(user.ID, user.Phone)
	if err != nil {
		logger.Errorf("Generate token pair failed: %v", err)
		return nil, errors.ErrSystem
	}

	// 11. 保存 refresh token 到数据库
	if err := authDAO.UpdateUserRefreshToken(user.ID, tokenPair.RefreshToken, tokenPair.RefreshExpiresAt); err != nil {
		logger.Errorf("Update user refresh token failed: %v", err)
	}

	// 12. 记录成功登录
	_ = authDAO.CreateLoginAttempt(&auth.LoginAttempt{
		Phone:       req.Phone,
		AttemptTime: time.Now(),
		IsSuccess:   true,
		ClientIP:    req.ClientIP,
		AttemptType: auth.LoginAttemptTypeSMS,
	})

	// 13. 清除登录限制
	_ = authDAO.ClearLoginLimit(req.Phone)

	logger.Infof("User login success: phone=%s, user_id=%d", req.Phone, user.ID)

	// 返回登录成功数据
	return &LoginData{
		AccessToken:      tokenPair.AccessToken,
		RefreshToken:     tokenPair.RefreshToken,
		User:             user,
		AccessExpiresAt:  tokenPair.AccessExpiresAt,
		RefreshExpiresAt: tokenPair.RefreshExpiresAt,
	}, nil
}
